package cn.buk.tms.eotms.dao;

import cn.buk.common.sc.CommonSearchCriteria;
import cn.buk.tms.eotms.entity.PaymentOrder;
import org.springframework.stereotype.Component;

import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import jakarta.transaction.Transactional;
import java.util.ArrayList;
import java.util.List;

@Component
@Transactional
public class PaymentOrderDaoImpl extends AbstractDao implements PaymentOrderDao {

	private final double ALIPAY_RATE = 0.015;  // 支付宝在线支付收取的手续费率

	@Override
	public int create(PaymentOrder order) {
		if (order == null) {
			throw new IllegalArgumentException("order cannot be null");
		}

//		order.setCreateDate(DateUtil.getCurDateTime());
		em.persist(order);

		return order.getId();
	}


	@Override
	public PaymentOrder updatePaymentOrderDone(String orderId, double totalAmount, final int status, String alipayTradeNo, String alipayBuyerId) {
		if (status != PaymentOrder.PAYMENT_ORDER_SUCCESS) {
			throw new RuntimeException("status is not consistent.");
		}

		List<PaymentOrder> orders =
						em.createQuery("select o from PaymentOrder o where o.tradeNo = :tradeNo and o.status = :status", PaymentOrder.class)
										.setParameter("tradeNo", orderId)
										.setParameter("status", PaymentOrder.PAYMENT_ORDER_WAITING_FOR_PAYMENT)
										.getResultList();
		if (orders == null || orders.size() < 1) {
			throw new RuntimeException("There is not a qualified payment order.");
		}

		PaymentOrder po = orders.get(0);
		if (po.getStatus() == status) {
			throw new RuntimeException("Payment order's status already is done.");
		}

		double alpha = Math.abs(po.getPrice() - totalAmount);
		if (alpha > 0.001) {
			throw new RuntimeException("Total amount is not equal.");
		}

		po.setStatus(status);
		po.setAlipayTradeNo(alipayTradeNo);
		po.setAlipayBuyerId(alipayBuyerId);
		em.merge(po);

		return po;
	}


	@Override
	public List<PaymentOrder> searchPaymentOrder(final int ownerId, final int enterpriseId, CommonSearchCriteria sc) {
		List<PaymentOrder> results = null;

		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<PaymentOrder> cq = cb.createQuery(PaymentOrder.class);
		Root<PaymentOrder> root = cq.from(PaymentOrder.class);
		root.alias("o");

		List<Predicate> predicates = new ArrayList<>();

		Predicate predicate = cb.conjunction();
		predicates.add(predicate);

//		predicate = cb.equal(root.get(PaymentOrder_.ownerEnterpriseId), ownerId);
//		predicates.add(predicate);
//
//
//		if (enterpriseId > 0) {
//			predicate = cb.equal(root.get(PaymentOrder_.enterpriseId), enterpriseId);
//			predicates.add(predicate);
//		}
//
//		if (sc.getStatus() == PaymentOrder.PAYMENT_ORDER_SUCCESS) {
//			predicate = cb.equal(root.get(PaymentOrder_.status), sc.getStatus());
//			predicates.add(predicate);
//		}


		////////////////////////
		// count items
		CriteriaQuery<Long> countCq = cb.createQuery(Long.class);
		Root<PaymentOrder> countRoot = countCq.from(PaymentOrder.class);
		countRoot.alias("o");

		countCq.select(cb.count(countRoot)).where(predicates.toArray(new Predicate[predicates.size()]));
		Long count = em.createQuery(countCq).getSingleResult();


		if (count > 0) {
			sc.getPage().setRowCount(count.intValue());

			//search block
			int firstPosition = (sc.getPage().getPageNo() - 1) * sc.getPage().getPageSize();
			cq.select(root).where(predicates.toArray(new Predicate[predicates.size()]));

			List<jakarta.persistence.criteria.Order> orderByes = new ArrayList<>();
			orderByes.add(cb.desc(root.get("id")));
			cq.orderBy(orderByes);

			sc.getPage().setRowCount(count.intValue());

			results = em.createQuery(cq)
					.setFirstResult(firstPosition)
					.setMaxResults(sc.getPageSize()).getResultList();

		}
		if (results == null) {
      results = new ArrayList<>();
    }
		return results;
	}

  @Override
  public PaymentOrder getPaymentOrderByTradeNo(String tradeNo) {
    List<PaymentOrder> list = em.createQuery("select o from PaymentOrder o where o.tradeNo = :tradeNo", PaymentOrder.class)
						.setParameter("tradeNo", tradeNo)
						.getResultList();

    return list.size() == 1 ? list.get(0): null;
  }

}
